// 分析命令  go tool pprof
// runtime/pprof：采集工具型应用运行数据进行分析《运行一次结束使用该方法》
// net/http/pprof：采集服务型应用运行时数据进行分析 《一直运行的服务可以使用该库》
// 如果你使用的是gin框架，那么推荐使用"github.com/DeanThompson/ginpprof"。
// 不管哪种方式，你的 HTTP 服务都会多出/debug/pprof endpoint，访问它会得到类似下面的内容

// runtime_pprof/main.go
package main

import (
	"flag"
	"fmt"
	"os"
	"runtime/pprof"
	"time"
)

// 一段有问题的代码
func logicCode() {
	var c chan int
	for {
		select {
		case v := <-c:
			fmt.Printf("recv from chan, value:%v\n", v)
		default:
			time.Sleep(time.Second)
		}
	}
}

func main() {
	var isCPUPprof bool
	var isMemPprof bool

	flag.BoolVar(&isCPUPprof, "cpu", false, "turn cpu pprof on")
	flag.BoolVar(&isMemPprof, "mem", false, "turn mem pprof on")
	flag.Parse()

	if isCPUPprof {
		file, err := os.Create("./cpu.pprof")
		if err != nil {
			fmt.Printf("create cpu pprof failed, err:%v\n", err)
			return
		}
		pprof.StartCPUProfile(file)  // 开始
		defer pprof.StopCPUProfile() // 停止分析
	}
	for i := 0; i < 8; i++ {
		go logicCode()
	}
	time.Sleep(20 * time.Second)
	if isMemPprof {
		file, err := os.Create("./mem.pprof")
		if err != nil {
			fmt.Printf("create mem pprof failed, err:%v\n", err)
			return
		}
		pprof.WriteHeapProfile(file) // 分析数据写入
		file.Close()                 // 文件关闭
	}
}

// 分析命令:go tool pprof cpu.pprof
// 想要图形化 就需要这个了::  brew install graphviz
// Windows: 下载graphviz 将graphviz安装目录下的bin文件夹添加到Path环境变量中。
// 在终端输入dot -version查看是否安装成功。 WIN 下载:https://graphviz.gitlab.io/_pages/Download/Download_windows.html

// go-torch和火焰图
// 安装:  go get -v github.com/uber/go-torch
// 安装 FlameGraph
// 要生成火焰图，需要事先安装 FlameGraph工具，
// 这个工具的安装很简单（需要perl环境支持），只要把对应的可执行文件加入到环境变量中即可。

// 下载安装perl：https://www.perl.org/get.html
// 下载FlameGraph：git clone https://github.com/brendangregg/FlameGraph.git
// 将FlameGraph目录加入到操作系统的环境变量中。
// Windows平台的同学，需要把go-torch/render/flamegraph.go文件中的GenerateFlameGraph按如下方式修改，然后在go-torch目录下执行go install即可

// 一般情况都是test 测试文件和测试的情况与性能分析搭配使用效果会更好
/*
 * @Author: your name
 * @Date: 2020-08-11 21:01:52
 * @LastEditTime: 2020-08-11 21:44:03
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \day01\demo6\main.go
 */
package main

import (
	"errors"
	"fmt"
	"strings"
)

func intSum2(x ...int) int {
	fmt.Printf("类型:%T  %v, \n", x, x)
	sum := 0
	for _, v := range x {
		sum = sum + v
	}
	return sum
}

func intSum3(y int, x ...int) int {
	fmt.Printf("类型:%T  %v, \n", x, x)
	sum := 0
	for _, v := range x {
		sum = sum + v
	}
	return sum + y
}

type calculation func(int, int) int

func add(x, y int) int {
	return x + y
}

func sub(x, y int) int {
	return x - y
}

func calc(x, y int, op func(int, int) int) int {
	return op(x, y)
}

func do(s string) (func(int, int) int, error) {
	switch s {
	case "+":
		return add, nil
	case "-":
		return sub, nil
	default:
		err := errors.New("无法识别的操作符")
		return nil, err
	}
}

func adder2(x int) func(int) int {
	fmt.Printf("执行中....\n")
	return func(y int) int { // 这个函数在内部，就是一个闭包
		return x + y
	}
}

func nameSuffixFunc(name string) func(string) string {

	return func(str string) string {
		if !strings.HasSuffix(str, name) {
			return str + name
		}
		return str
	}
}

func calcc(base int) (func(int) int, func(int) int) {
	add := func(i int) int {
		base += i
		return base
	}

	sub := func(i int) int {
		base -= i
		return base
	}
	return add, sub
}

func main() {
	a := intSum2()
	b := intSum2(1, 2, 3)
	c := intSum2(10, 20, 30)
	fmt.Printf("a==%d|b==%d|c==%d\n", a, b, c)
	d := intSum3(10, 12, 321, 43, 54)
	e := intSum3(21)
	fmt.Printf("d==%d|e==%d|\n", d, e)
	fmt.Println("=============函数进阶==============")
	var cc calculation
	cc = add
	cr := cc(1, 2)
	fmt.Println(cr)
	fmt.Println("=============函数进阶2回调函数==============")
	r1 := calc(1, 1, cc)
	fmt.Println(r1)
	fmt.Println("=============函数进阶3回调函数==============")
	r2, _ := do("+")
	fmt.Println(r2(1, 2))
	fmt.Println("=============函数进阶4 匿名函数==============")
	add1 := func(x, y int) int {
		return x + y
	}
	r3 := add1(10, 20)
	fmt.Println(r3)
	fmt.Println("=============函数进阶5闭包==============")
	r4 := adder2(3)
	r5 := r4(6)
	fmt.Println(r5)
	fmt.Println("=============函数进阶5闭包进阶==============")
	str1 := nameSuffixFunc("a")
	strr := str1("abc")
	fmt.Println(strr)
	fmt.Println("=============函数进阶6闭包进阶==============")

	f1, f2 := calcc(10)
	fmt.Println(f1(1), f2(2)) //11 9
	fmt.Println(f1(3), f2(4)) //12 8
	fmt.Println("=============函数==============")

}

//   经典题目

// func f1() int {
// 	x := 5
// 	defer func() {
// 		x++
// 	}()
// 	return x
// }

// func f2() (x int) {
// 	defer func() {
// 		x++
// 	}()
// 	return 5
// }

// func f3() (y int) {
// 	x := 5
// 	defer func() {
// 		x++
// 	}()
// 	return x
// }
// func f4() (x int) {
// 	defer func(x int) {
// 		x++
// 	}(x)
// 	return 5
// }
// func main() {
// 	fmt.Println(f1())
// 	fmt.Println(f2())
// 	fmt.Println(f3())
// 	fmt.Println(f4())
// }
